package com.example.logaop.aop;

import cn.hutool.json.JSONUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @auther zzyy
 * @create 2022-11-19 12:34
 */
@Aspect
@Component
public class LogRecordAspect
{

    //切面类+连接点joinpoint+切入点pointCut
    @Pointcut("@annotation(com.example.logaop.aop.LogRecordAnnotation)")
    public void pointCut(){}

    //设计时，一定要注意异步，横切性关注点，另外用线程处理，和主线程解耦，不打扰
    ExecutorService threadPool = new ThreadPoolExecutor(
            1,
            1,
            1L,
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(200));

    /**
     *
     * @param proceedingJoinPoint
     * @return
     * @throws Throwable 有异常就不记录流水，直接抛出
     */
    @Around("pointCut()")
    public Object aroundNotify(ProceedingJoinPoint proceedingJoinPoint) throws Throwable
    {
        Object retValue = proceedingJoinPoint.proceed();

        try
        {
            Object finalRetValue = retValue;
            threadPool.execute(() -> {
                try {
                    MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
                    LogRecordAnnotation logRecordAnnotation = methodSignature.getMethod().getDeclaredAnnotation(LogRecordAnnotation.class);
                    //上面来的是不同的业务实体(订单、vip订单、仓库、积分,但是下面的日志模型就是一个)

                    // 记录订单id、商铺id、积分id等不同属性id，该如何处理?难道各种判断？
                    Class<? extends Convert> convert = logRecordAnnotation.convert();
                    Convert logConvert = convert.newInstance();
                    System.out.println("logConvert----"+logConvert.toString());
                    System.out.println("----参数： "+ proceedingJoinPoint.getArgs()[0]);
                    LogRecord logRecord = logConvert.convert(proceedingJoinPoint.getArgs()[0]);

                    logRecord.setDesc(logRecordAnnotation.desc());
                    logRecord.setResult(finalRetValue.toString());
                    System.out.println("===记录流水： "+ JSONUtil.toJsonStr(logRecord));
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }finally {
                    threadPool.shutdown();
                }
            });
        }catch (Exception e){
            e.printStackTrace();
        }

        return retValue;
    }

    /*设计痛点和难点 ，不想各种判断，你如何处理独有部分？
    @Around("pointCut()")
    public Object aroundNotify(ProceedingJoinPoint proceedingJoinPoint) throws Throwable
    {
        Object retValue = proceedingJoinPoint.proceed();//主业务逻辑，保存订单

        try
        {
            threadPool.execute(() -> {
                MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
                LogRecordAnnotation logRecordAnnotation = methodSignature.getMethod().getDeclaredAnnotation(LogRecordAnnotation.class);
                //上面来的是不同的业务实体(订单、vip订单、仓库、积分,但是下面的日志模型就是一个)
                LogRecord logRecord = new LogRecord();
                //按照统一日志模型LogRecord进行记录
                logRecord.setDesc(logRecordAnnotation.desc());
                logRecord.setResult(retValue);
                // 记录订单id、商铺id、积分id等不同属性id，该如何处理?难道各种判断？
            });

        }catch (Exception e){
            e.printStackTrace();
        }

        return retValue;
    }*/
}

